//@author A0105740R
package rightnow.parser.cmdline;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * This class is a driver class for all command parsers.<br>
 * It receives a string, parses it and stores the result in CmdParserBucket.
 */
public class CommandParser {	
	private static final Logger log = 
			LoggerFactory.getLogger(CommandParser.class);
	
	private static final int POSITION_COMMAND = 0;
	private static final int POSITION_OTHER = 1;
	
	private static final int NUM_TOKEN_CMD_ONLY = 1;
	private static final int NUM_TOKEN_REQUIRE_PARAM = 2;
	private static final int NUM_MAX_SPLIT= 2;
	
	private static final String FATAL_ERROR_PARSER_INCOMPLETE =
			"debug use only: command parser is incomplete";
	
	/**
	 * Parses the text and stores the result in a command parser bucket.
	 * @param bucket - not null
	 * @param text
	 * @throws CmdParserException
	 */
	public void parseInto(CmdParserBucket bucket, String text) 
			throws CmdParserException {
		assert bucket != null;
		
		if (text == null) {
			throw new CmdParserException(CmdParserErrorMsg.ERROR_EMPTY_COMMAND);
		}
		
		String[] tokens = text.trim().split("\\s+", NUM_MAX_SPLIT);
		
		int numTokens = tokens.length;
		
		bucket.setCmdType(CmdTypeParser.parse(tokens[POSITION_COMMAND], 
				numTokens));
		
		if (!isValidTokenNum(bucket.getCmdType(), numTokens)) {
			throw new CmdParserException(
					String.format(CmdParserErrorMsg.ERROR_NUM_ARG,
					CmdParserErrorMsg.getCmdName(bucket.getCmdType())));
		}
		
		switch (bucket.getCmdType()) {
		case ADD:
			bucket.setTask(CmdTaskParser.INSTANCE.parse(tokens[POSITION_OTHER]));
			break;
		case EDIT:
			CmdEditParser.parseInto(bucket, tokens[POSITION_OTHER]);
			break;
		case DELETE:
			CmdDelParser.parseInto(bucket, tokens[POSITION_OTHER]);
			break;
		case DONE:
		case UNDONE:
		case PIN:
		case UNPIN:
			try {
				bucket.setInt(Integer.parseInt(tokens[POSITION_OTHER]));
			}
			catch (NumberFormatException e) {
				throw new CmdParserException(CmdParserErrorMsg.ERROR_FORMAT_INDEX);
			}
			break;
		case PAGE:
			try {
				bucket.setInt(Integer.parseInt(tokens[POSITION_OTHER]));
			}
			catch (NumberFormatException e) {
				throw new CmdParserException(CmdParserErrorMsg.ERROR_FORMAT_PAGE_NUM);
			}
			break;
		case SEARCH:
			bucket.setString(tokens[POSITION_OTHER]);
			break;
		case ALL:
		case NOW:
		case UNDO:
		case REDO:
		case NEXT:
		case PREV:
			break;
		default:
			log.error(FATAL_ERROR_PARSER_INCOMPLETE);
			assert false;
		}
	}
	
	private boolean isValidTokenNum(CommandType cmdType, int tokenNum) {
		switch (cmdType) {
		case ADD:
		case DELETE:
		case EDIT:
		case DONE:
		case UNDONE:
		case PIN:
		case UNPIN:
		case PAGE:
		case SEARCH:
			return tokenNum == NUM_TOKEN_REQUIRE_PARAM;
		case ALL:
		case NOW:
		case REDO:
		case UNDO:
		case NEXT:
		case PREV:
			return tokenNum == NUM_TOKEN_CMD_ONLY;
		default:
			log.error(FATAL_ERROR_PARSER_INCOMPLETE);
			assert false;
			return false;
		}
	}
}
